import isErrorHandlerTriggered from '../../../../lib/middleware/isErrorHandlerTriggered.js';
import { render } from '../../../../lib/response/render.js';
import { get } from '../../../../lib/util/get.js';
import { getConfig } from '../../../../lib/util/getConfig.js';
import isDevelopmentMode from '../../../../lib/util/isDevelopmentMode.js';
import { getValueSync } from '../../../../lib/util/registry.js';
import {
  getPageMetaInfo,
  setPageMetaInfo
} from '../../../../modules/cms/services/pageMetaInfo.js';
import { AppStateContextValue, Config } from '../../../../types/appContext.js';
import { EvershopRequest } from '../../../../types/request.js';
import { loadWidgetInstances } from '../../../cms/services/widget/loadWidgetInstances.js';
import { getContextValue } from '../../../graphql/services/contextHelper.js';
import { getNotifications } from '../../services/notifications.js';

export default async (request: EvershopRequest, response, next) => {
  try {
    /** If a rejected middleware called next(error) without throwing an error */
    if (isErrorHandlerTriggered(response)) {
      return;
    } else {
      const route = request.currentRoute;

      // Check if `$body` is empty or not. If yes, we consider the content is already generated by previous middlewares
      if (response.$body && response.$body !== '') {
        response.send(response.$body);
      } else {
        response.context.route = {
          id: route.id,
          path: route.path,
          method: route.method,
          isApi: route.isApi,
          isAdmin: route.isAdmin
        };
        setPageMetaInfo(request, {
          route: {
            id: route.id,
            path: route.path,
            url: getContextValue(request, 'currentUrl'),
            params: request.params
          }
        });
        let widgetInstances;
        // Check if we are in the test mode
        if (process.env.NODE_ENV === 'test') {
          widgetInstances = [];
        } else {
          widgetInstances = await loadWidgetInstances(request);
        }
        widgetInstances = widgetInstances.map((widget) => {
          const newWidget = {
            sortOrder: widget.sortOrder,
            areaId: widget.areaId,
            type: widget.type,
            id: `e${widget.uuid.replace(/-/g, '')}`
          };
          if (route.isAdmin) {
            newWidget.areaId = 'widget_setting_form';
          }
          return newWidget;
        });
        response.locals.widgets = widgetInstances;
        if (
          (isDevelopmentMode() &&
            request.query &&
            request.query.fashRefresh === 'true') ||
          (request.query && request.query.ajax === 'true')
        ) {
          const pageMeta = getPageMetaInfo(request);
          const appConfig = getValueSync<Config>(
            'appConfig',
            {
              tax: {
                priceIncludingTax: getConfig<boolean>(
                  'pricing.tax.price_including_tax',
                  false
                )
              },
              catalog: {
                imageDimensions: {
                  width: getConfig<number>('catalog.product.image.width', 1200),
                  height: getConfig<number>(
                    'catalog.product.image.height',
                    1200
                  )
                }
              },
              pageMeta: pageMeta
            },
            { request, response },
            (value) =>
              value && typeof value === 'object' && !Array.isArray(value)
          );
          const config = Object.assign({}, appConfig, { pageMeta });

          response.json({
            success: true,
            eContext: {
              graphqlResponse: get<Record<string, any>>(
                response,
                'locals.graphqlResponse',
                {}
              ),
              config: config,
              propsMap: get(response, 'locals.propsMap', {}),
              widgets: widgetInstances
            } as AppStateContextValue
          });
        } else {
          render(request, response);
        }
      }
    }
  } catch (error) {
    if (!isErrorHandlerTriggered(response)) {
      next(error);
    } else {
      // Do nothing here since the next(error) is already called
      // when the error is thrown on each middleware
    }
  }
};
